package com.rfid.a252robot.task;

import android.os.Handler;
import android.text.TextUtils;

import com.rfid.a252robot.bean.Log;
import com.rfid.a252robot.event.BooksInfoEvent;
import com.rfid.a252robot.event.BorrowEvent;
import com.rfid.a252robot.event.BoxCloseEvent;
import com.rfid.a252robot.event.BoxOpenEvent;
import com.rfid.a252robot.event.RestoreEvent;
import com.rfid.a252robot.event.RestoreFailEvent;
import com.rfid.a252robot.event.TaskEvent;
import com.rfid.a252robot.net.BookLibApi;
import com.rfid.a252robot.net.BoxLibApi;
import com.rfid.a252robot.net.bean.BookInfoRespon;
import com.rfid.a252robot.net.bean.UploadBook;
import com.rfid.acs.bean.BookBean;
import com.rfid.acs.net.bean.RestoreBookBean;
import com.rfid.common.log.LogUtils;
import com.rfid.db.bean.Book;
import com.rfid.db.bean.FailBook;
import com.rfid.db.bean.OperateInfo;
import com.rfid.manager.BookManager;
import com.rfid.manager.DBManager;
import com.rfid.manager.DoorBoxManager;
import com.rfid.manager.LogUploadManager;
import com.rfid.manager.ReadTagManager;
import com.rfid.util.Util;
import com.shrfid.module_base.entity.TagEntity;
import com.shrfid.rfidsdk.tag.NewReadTagManager;
import com.spectre.generate.ConfigManager;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

public class BorrowRestoreTask implements Runnable, DoorBoxManager.Listener,ITask{

    int boxNum;
    String reader;
    String pwd;
    boolean borrow;
    boolean mQueryLock;
    Handler mHandler;
    Executor mExecutor = Executors.newSingleThreadExecutor();

    public BorrowRestoreTask(int boxNum,boolean borrow,String reader,String pwd,Handler handler) {
        this.borrow = borrow;
        this.boxNum = boxNum;
        this.reader = reader;
        this.pwd = pwd;
        mHandler = handler;
        if (mHandler == null) {
            mHandler = new Handler();
        }
    }

    public void setBoxNum(int boxNum) {
        this.boxNum = boxNum;
    }

    public void setHandler(Handler handler) {
        mHandler = handler;
    }

    public int getBoxNum() {
        return boxNum;
    }

    public boolean isBorrow() {
        return borrow;
    }

    public boolean isBoxClose() {
        return !mQueryLock;
    }

    @Override
    public void run() {
        LogUtils.v("borrow = " + borrow + ",boxNum = " + boxNum + ",reader = " + reader);
        List<Book> books = DBManager.getBooks(boxNum);
        for (Book book : books) {
            book.setPreBorrowReader(reader);
            DBManager.updateBook(book);
        }
        DoorBoxManager.INSTANCE.addListener(this);
        DoorBoxManager.INSTANCE.openLock((byte) boxNum);
        System.out.println("set  mQueryLock = true");
        mQueryLock = true;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (mQueryLock) {
            System.out.println("queryOpenStatus boxNum = " + boxNum);
            DoorBoxManager.INSTANCE.queryOpenStatus((byte) boxNum);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void onLockOpen(int num, boolean success) {
        LogUtils.v("onLockOpen num = " + num + ",success = " + success);
        EventBus.getDefault().post(new BoxOpenEvent(num,success));
        if (num == boxNum && !success) {
            mQueryLock = false;
            releaseListener();
            Book book = new Book();
            book.setBoxNum(boxNum);
            book.setPreBorrowReader(reader);
            DBManager.addOperateLog(book, OperateInfo.OPERATE_OPEN_FAIL);
        }
    }

    @Override
    public void onLockOpenStatus(int num, boolean open) {
        LogUtils.v("onLockOpenStatus num = " + num + ",open = " + open + ",cBoxNum = " + boxNum);
        if (num == boxNum) {
            if (!open) {
                System.out.println("set mQueryLock = false");
                ReadTagManager.INSTANCE.selectAntenna(Util.getAntenna(boxNum));
                if (borrow) {
                    List<Book> books = DBManager.getBooks(boxNum);
                    int time = ConfigManager.INSTANCE.getGlobalConfig().getReadCount();
                    while (time > 0) {
                        List<TagEntity> tagEntities = ReadTagManager.INSTANCE.readTags();
                        if (books.size() == 0) {
                            return;
                        }
                        for (TagEntity tagEntity : tagEntities) {
                            for (int i = 0; i < books.size(); i++) {
                                Book book = books.get(i);
                                if (book.getBarcode().equals(tagEntity.getBookNo()) && !TextUtils.isEmpty(book.getPreBorrowReader())) {
                                    book.setPreBorrowReader(null);
                                    DBManager.updateBook(book);
                                }
                            }
                        }
                        time--;
                    }
                    doBorrow(boxNum);
                    releaseListener();
                } else {
                    List<Book> books = DBManager.getBooks();
                    List<String> add = new ArrayList<>();
                    boolean hasUnkownBarcode = false;
                    int time = ConfigManager.INSTANCE.getGlobalConfig().getReadCount();
                    while (time > 0 && !hasUnkownBarcode) {
                        List<TagEntity> tagEntities = ReadTagManager.INSTANCE.readTags();
                        System.out.println("tagEntities = " + tagEntities);
                        for (TagEntity tagEntity : tagEntities) {
                            if (TextUtils.isEmpty(tagEntity.getBookNo())) {
                                hasUnkownBarcode = true;
                                break;
                            }
                            if (!add.contains(tagEntity.getBookNo())) {
                                boolean c = false;
                                for (Book book : books) {
                                    if (book.getBarcode().equals(tagEntity.getBookNo())) {
                                        c = true;
                                    }
                                }
                                if (!c) {
                                    add.add(tagEntity.getBookNo());
                                }
                            }
                        }
                        time--;
                    }
                    if (hasUnkownBarcode) {
                        EventBus.getDefault().post(new RestoreFailEvent("存在非本馆书籍，请取出重新归还"));
                        DoorBoxManager.INSTANCE.openLock((byte) boxNum);
                        return;
                    }
                    if (add.size() > 3) {
                        EventBus.getDefault().post(new RestoreFailEvent("每个格子最多归还3本书，请取出重新归还"));
                        DoorBoxManager.INSTANCE.openLock((byte) boxNum);
                        return;
                    }
                    System.out.println("restore = " + add);
                    doRestore(num, add);
                    releaseListener();
                }
                mQueryLock = false;
            } else {
                System.out.println("-------");
                //没这需求了
//                if (!borrow) {
//                    List<Book> books = DBManager.getBooks();
//                    List<String> add = new ArrayList<>();
//                    while (mQueryLock) {
//                        List<TagEntity> tagEntities = ReadTagManager.INSTANCE.readTags();
//                        System.out.println("tagEntities = " + tagEntities);
//                        for (TagEntity tagEntity : tagEntities) {
//                            if (!books.contains(tagEntity.getBookNo()) && !add.contains(tagEntity.getBookNo())) {
//                                add.add(tagEntity.getBookNo());
//                            }
//                        }
//                    }
//                    notifyBooks(boxNum,add);
//                }
            }
        }
        if (!open) {
            EventBus.getDefault().post(new BoxCloseEvent(boxNum));
        }
    }

    private void releaseListener() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                LogUtils.v("releaseListener boxNum = " + boxNum);
                DoorBoxManager.INSTANCE.removeListener(BorrowRestoreTask.this);
                EventBus.getDefault().post(new TaskEvent(BorrowRestoreTask.this));
            }
        });
    }

    private void notifyBooks(int boxNum,List<String> barcodes) {
        BookManager.INSTANCE.searchBooksWithBarcode(barcodes)
                .subscribe(new Consumer<List<BookBean>>() {
                    @Override
                    public void accept(List<BookBean> bookBeans) throws Exception {
                        List<Book> books = new ArrayList<>();
                        for (BookBean bean : bookBeans) {
                            Book book = new Book();
                            book.setBarcode(bean.getBookId());
                            book.setName(bean.getBookName());
                            book.setBoxNum(boxNum);
                            books.add(book);
                        }
                        System.out.println("notifyBooks = " + books);
                        EventBus.getDefault().post(new BooksInfoEvent(books));
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        LogUtils.e(throwable);
                    }
                });
    }

    private void doBorrow(int boxNum) {
        List<Book> books = DBManager.getBooks(boxNum);
        System.out.println("doBorrow thread = " + Thread.currentThread().getName());
        System.out.println("doBorrow query = " + books);
        for (Book book : books) {
            String reader = book.getPreBorrowReader();
            if (TextUtils.isEmpty(reader)) {
                continue;
            }
            System.out.println("borrow " + book);
            DBManager.deleteBook(book.getBarcode());
            BookManager.INSTANCE.borrowBook(book.getBarcode(),reader,null)
                    .observeOn(Schedulers.io())
                    .map(new Function<BookBean, BookBean>() {
                        @Override
                        public BookBean apply(BookBean bookBean) throws Exception {
                            sendInfoToServer(book);
                            return bookBean;
                        }
                    })
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<BookBean>() {
                        @Override
                        public void accept(BookBean bookBean) throws Exception {
                            System.out.println("accept thread = " + Thread.currentThread().getName());
//                            if (bookBean.isBorrowSuccess()) {
                            EventBus.getDefault().post(new BorrowEvent(book));
//                            }
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) throws Exception {
                            saveFailBorrow(book);
                            EventBus.getDefault().post(new BorrowEvent(book));
                        }
                    });
            Log log = new Log();
            log.setReaderNo(reader);
            log.setOpType("借书");
            log.setBookName(book.getName());
            log.setBookBarcode(book.getBarcode());
            LogUploadManager.INSTANCE.upload(log);
        }
    }

    private void saveFailBorrow(Book book) {
        FailBook fb = new FailBook();
        fb.setAuthor(book.getAuthor());
        fb.setBarcode(book.getBarcode());
        fb.setBoxNum(book.getBoxNum());
        fb.setReader(reader);
        fb.setPwd(pwd);
        fb.setBorrow(true);
        fb.setName(book.getName());
        DBManager.insertFailBook(fb);
    }

    private void saveFailRestore(Book book) {
        FailBook fb = new FailBook();
        fb.setBarcode(book.getBarcode());
        fb.setBoxNum(book.getBoxNum());
        fb.setBorrow(false);
        DBManager.insertFailBook(fb);
    }

    private void doRestore(int num, List<String> barcodes) {
        notifyBooks(boxNum,barcodes);
        if (true) {
            return;
        }
        for (String barcode : barcodes) {
            Book book = new Book();
            book.setBoxNum(num);
            book.setBarcode(barcode);
            DBManager.insertBook(book);
            BookManager.INSTANCE.restoreBook(barcode)
                    .observeOn(Schedulers.io())
                    .map(new Function<RestoreBookBean, Book>() {
                        @Override
                        public Book apply(RestoreBookBean restoreBookBean) throws Exception {
                            System.out.println("restoreBookBean = " + restoreBookBean);
                            Book book1 = DBManager.getBook(barcode);
                            System.out.println("book1 = " + book1);
                            if (book1 != null) {
                                if (restoreBookBean.isSuccess()) {
                                    book1.setCanBorrow(true);
                                }
                                book1.setName(restoreBookBean.getBookName());
                                DBManager.updateBook(book1);
                                queryIsbn(book1);
                                sendInfoToServer(book1);
                            }
                            if (!restoreBookBean.isSuccess()) {
//                                DBManager.deleteBook(book1);
                                LogUtils.v("restoreBook fail!keep book in db!" + restoreBookBean.getHintMessage());
//                                return null;
                            }
                            return book1;
                        }
                    }).subscribe(new Consumer<Book>() {
                @Override
                public void accept(Book o) throws Exception {
                    if (o != null) {
                        EventBus.getDefault().post(new RestoreEvent(o));
                    }
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(Throwable throwable) throws Exception {
                    throwable.printStackTrace();
                    LogUtils.e(throwable);
                    saveFailRestore(book);
                    EventBus.getDefault().post(new RestoreEvent(book));
                }
            });
            Log log = new Log();
            log.setBookBarcode(barcode);
            log.setOpType("还书");
            LogUploadManager.INSTANCE.upload(log);
        }
    }

    private void sendInfoToServer(Book book) {
        if (!book.getCanBorrow()) {
            return;
        }
        mExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    BoxLibApi.INSTANCE.uploadBook(book, UploadBook.TYPE_NORMAL);
                } catch (Exception e) {
                    LogUtils.e(e);
                }
            }
        });
    }

    private void queryIsbn(Book book) {
        mExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    BookInfoRespon info = BookLibApi.INSTANCE.getBookInfo(book.getBarcode());
                    List<BookInfoRespon.DataBeanX.DataBean.ItemsBean> itemsBeans = info.getData().getData().getItems();
                    if (itemsBeans != null && itemsBeans.size() > 0) {
                        List<BookInfoRespon.DataBeanX.DataBean.ItemsBean.IdentifiersBean> ids = itemsBeans.get(0).getIdentifiers();
                        if (ids != null&&ids.size() > 0) {
                            String isbn = ids.get(0).getValue();
                            book.setIsbn(isbn);
                            DBManager.updateBook(book);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BorrowRestoreTask that = (BorrowRestoreTask) o;
        return boxNum == that.boxNum &&
                borrow == that.borrow;
    }

    @Override
    public int hashCode() {
        return Objects.hash(boxNum, borrow);
    }

    @Override
    public String toString() {
        return "BorrowRestoreTask{" +
                "boxNum=" + boxNum +
                ", reader='" + reader + '\'' +
                ", borrow=" + borrow +
                ", mQueryLock=" + mQueryLock +
                ", mHandler=" + mHandler +
                '}';
    }
}
